package org.lboot.flow.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Validator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.lboot.core.auth.anno.CheckRole;
import org.lboot.core.domain.ResponseDTO;
import org.lboot.core.exception.BusinessException;
import org.lboot.flow.module.define.FlowDefine;
import org.lboot.flow.module.define.FlowDefineService;
import org.lboot.flow.module.define.history.FlowDefineHistory;
import org.lboot.flow.module.define.history.FlowDefineHistoryService;
import org.lboot.flow.module.define.params.FlowDefineCreateParams;
import org.lboot.flow.module.define.params.FlowDefineQueryParams;
import org.lboot.flow.module.define.params.FlowDefineUpdateParams;
import org.lboot.flow.parser.FlowParser;
import org.lboot.jpa.utils.JpaDataUtil;
import org.lboot.starter.plugin.rsr.RsrTree;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.Predicate;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("flow")
@Api(tags = "流程定义")
@RsrTree("流程引擎")
@AllArgsConstructor
public class FlowDefineController {
    FlowDefineService defineService;


    FlowDefineHistoryService historyService;

    // 允许自定义注入
    List<FlowParser> flowParsers;

    //@ApiLog("流程定义")
    @PostMapping("define")
    @ApiOperation(value = "流程定义新增")
   // @CheckRole(orPerm = "flow:define:create")
    public ResponseDTO<Object> defineCreate(@Validated @RequestBody FlowDefineCreateParams params){
        FlowDefine define = new FlowDefine();
        BeanUtil.copyProperties(params,define, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        boolean isMatch = false;
        for (FlowParser parser:flowParsers){
            if (parser.type().equals(params.getFlowDefineType())){
                // 设置流程定义
                isMatch = true;
                define.setNodeList(parser.parser(params.getFlowDefine()));
                break;
            }
        }
        if (!isMatch){
            return ResponseDTO.wrap(HttpStatus.NOT_FOUND,"未找到对应的解析策略");
        }
        // 不允许重复的流程定义编码
        List<FlowDefine> defines = defineService.getFlowByCode(params.getFlowCode());
        if (!defines.isEmpty()){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"存在重复流程定义编码");
        }
        return ResponseDTO.succData(
                //define
                defineService.saveOne(define)
        );

    }

    @Data
    @ApiModel(value = "解析参数")
    static
    public class DefineParserParams{
        @NotBlank(message = "流程定义不可为空")
        String flowDefine;

        @NotBlank(message = "流程定义类型不可为空")
        @ApiModelProperty(value = "流程定义类型")
        String flowDefineType;
    }

    @PostMapping("define/parser")
    @ApiOperation(value = "流程定义解析")
    public ResponseDTO<Object> defineParser(@Validated @RequestBody DefineParserParams params){
        for (FlowParser parser:flowParsers){
            if (parser.type().equals(params.getFlowDefineType())){
                // 设置流程定义
                return ResponseDTO.succData(
                        parser.parser(params.getFlowDefine())
                );
            }
        }
        return ResponseDTO.wrap(HttpStatus.NOT_FOUND,"未找到对应的解析策略");
    }




    @DeleteMapping("define/{id}")
    @ApiOperation(value = "流程定义删除",notes = "")
    // @CheckRole(orPerm = "flow:define:delete")
    public ResponseDTO<Object> defineDelete(@PathVariable("id") String id){
        defineService.deleteOne(id);
        return ResponseDTO.succMsg("删除成功");
    }


    @PutMapping("define")
    @ApiOperation(value = "流程定义更新")
    // @CheckRole(orPerm = "flow:define:update")
    public ResponseDTO<Object> defineUpdate(@Validated @RequestBody FlowDefineUpdateParams params){
        FlowDefine define = defineService.getOneUnwrap(params.getId());
        FlowDefineHistory history = new FlowDefineHistory();
        BeanUtil.copyProperties(define,history,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        // ID
        history.setId(null);

        // 历史记录写入
        historyService.saveOne(history);
        // 记录
        BeanUtil.copyProperties(params,define,CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        return ResponseDTO.succData(
                defineService.updateOne(define)
        );
    }

    @GetMapping("define/all")
    @ApiOperation(value = "全部流程定义")
    public ResponseDTO<Object> listAllDefine(){
        List<FlowDefine> defines = defineService.getAll();
        return ResponseDTO.succData(
                defines
        );
    }

    @GetMapping("define")
    @ApiOperation(value = "流程定义列表")
    public ResponseDTO<Object> defineQueryList(FlowDefineQueryParams params){
        Pageable pageable = JpaDataUtil.buildPageable(params);
        // 构建谓词查询
        Specification<FlowDefine> spec = (root, query, cb) -> {
            List<Predicate> list = new ArrayList<>();
            if (Validator.isNotEmpty(params.getSearchKey())){
                Predicate p1 = cb.like(root.get("flowDefineCode"),   params.getSearchKey() + "%");

                Predicate p2 = cb.like(root.get("flowName"),   params.getSearchKey() + "%");
                //Predicate p3 = cb.like(root.get("userName"),   params.getSearchKey() + "%");
                list.add(cb.or(p1,p2));
            }
            // 在选择分组内
            if (Validator.isNotEmpty(params.getGroups()) && !params.getGroups().isEmpty()){
                // 条件不为空
                Predicate p1 = root.get("flowGroup").in(params.getGroups());
                list.add(p1);
            }
            if (Validator.isNotEmpty(params.getStatus())){
                Predicate p2 = cb.equal(root.get("status").as(Integer.class),params.getStatus());
                list.add(p2);
            }

            Predicate[] predicates = new Predicate[list.size()];
            return cb.and(list.toArray(predicates));
        };
        return ResponseDTO.succData(
                defineService.getAll(pageable,spec)
        );
    }

    @SneakyThrows
    @GetMapping("define/{id}")
    @ApiOperation(value = "流程定义查询")
    public ResponseDTO<Object> defineQuery(@PathVariable("id") String id){
        FlowDefine define = defineService.getOneUnwrap(id);
        Map<String,Object> resMap = BeanUtil.beanToMap(define);
        return ResponseDTO.succData(
                resMap
        );
    }



    @GetMapping("define/{code}/history")
    @ApiOperation(value = "流程定义历史版本")
    public ResponseDTO<Object> defineQueryHistory(@PathVariable("code") String code){
        FlowDefineHistory history = new FlowDefineHistory();
        history.setFlowCode(code);
        Example<FlowDefineHistory> example = Example.of(history);
        List<FlowDefineHistory> histories = historyService.getExample(example);
        return ResponseDTO.succData(
                histories
        );
    }

    @GetMapping("define/groups")
    @ApiOperation(value = "流程定义分组")
    public ResponseDTO<Object> defineGroup(){
        return ResponseDTO.succData(
                defineService.getDistinctGroup()
        );
    }
}
